//=============================================================================
//
//   Copyright (C) 2020 All rights reserved.
//
//   Filename:		mod.rs
//
//   Author: Wang Zhecheng - wangzhecheng@yeah.net
//
//   Date: 2020-11-06 14:27
//
//   Last Editors: Wang Zhecheng - wangzhecheng@yeah.net
//
//   Last modified:	2020-11-06 20:41
//
//   Description:
//
//=============================================================================
use crate::dimension::DimType;
use crate::Real;

macro_rules! material_impl {
    (CommonParameters:
        $($cparam:ident$(($crename:expr))?:$cparamtype:ty),*;
    $($mat:ident$(:
        $($sparam:ident$(($srename:expr))?:$sparamtype:ty),*)?);*) => {
        #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
        struct CommonParameters{
            $(
                $(#[serde(rename = $crename)])?
                $cparam:$cparamtype
            ),*
        }
        pub trait CommonParameterGetter{
            $(
                paste::paste!{
                    fn [< get_ $cparam >](&self)->$cparamtype;
                }
            )*
        }
        $(
            #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
            pub struct $mat<DT:DimType>{
                id: Option<usize>,
                #[serde(skip)]
                _marker: std::marker::PhantomData<DT>,
                #[serde(flatten)]
                common:CommonParameters,
                $( $(
                $(#[serde(rename = $srename)])?
                $sparam:$sparamtype
                ),*)?
            }
        )*
        #[derive(Debug, serde::Deserialize)]
        #[serde(untagged)]
        pub enum Material<DT: DimType> {
            $($mat($mat<DT>),)*
        }
    };
}

material_impl!(
    CommonParameters:
        id: Option<usize>,
        volume_weight: Real,
        elastic_modulus: Real,
        elastic_poisson: Real,
        friction_angle: Real,
        dilation_angle: Real,
        cohesion: Real,
        perm("permeability"): nalgebra::Vector3<Real>,
        k_ic("K_IC"): Real,
        zeta: Real;
    // -------------------
    Elastic;
    DuncanChang:
        rf("Rf"):Real,
        k("K"):Real,
        n:Real,
        g("G"):Real,
        f("F"):Real,
        d("D"):Real
);

#[test]
fn serde() {
    use crate::dimension::PlaneStrain;
    let data = r#"
        {
            "id": 2,
            "type": "elastic",
            "volume_weight": 19,
            "friction_angle": 30,
            "dilation_angle": 30,
            "cohesion": 10,
            "permeability": [1e-5,1e-5, 1e-5 ],
            "zeta": 0.1,
            "K_IC": 2.9,
            "elastic_modulus": 1000000.0,
            "elastic_poisson": 0.3
        }"#;
    let mat: Material<PlaneStrain> = serde_json::from_str(data).unwrap();
    println!("{:?}", mat);
    // assert_eq!(mat.get_volume_weight(), 19 as Real);
    // assert_eq!(mat.get_elastic_poisson(), 0.3 as Real);
}
